package com.server.common.security;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Properties;

import com.server.common.utils.PathUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class RSASignUtils {

	public static final String KEY_ALGORTHM = "RSA";
	public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

	/**
	 * 根据文件名获取秘钥
	 * 
	 * @param keyName
	 * @return
	 * @throws Exception
	 */
	public static String getKeyByKeyFileName(String keyName) throws Exception {
		try {
			Properties properties = PathUtils
					.getProperties("application.properties");
			String keyPath = properties.getProperty("publicKeyPath");
			BufferedReader br = new BufferedReader(new FileReader(keyPath
					+ keyName));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null) {
				if (readLine.startsWith("-")) {
					continue;
				}
				sb.append(readLine);
			}
			br.close();
			return sb.toString();
		} catch (IOException e) {
			throw new Exception(e.getMessage());
		} catch (NullPointerException e) {
			throw new Exception("秘钥输入流为空");
		}
	}

	/**
	 * 用私钥对信息生成数字签名
	 * 
	 * @param data
	 *            //加密数据
	 * @param privateKey
	 *            //私钥
	 * @return
	 * @throws Exception
	 */
	public static String sign(byte[] data, String privateKey) throws Exception {
		// 解密私钥
		byte[] keyBytes = decryptBASE64(privateKey);
		// 构造PKCS8EncodedKeySpec对象
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
				keyBytes);
		// 指定加密算法
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
		// 取私钥匙对象
		PrivateKey privateKey2 = keyFactory
				.generatePrivate(pkcs8EncodedKeySpec);
		// 用私钥对信息生成数字签名
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initSign(privateKey2);
		signature.update(data);

		return encryptBASE64(signature.sign());
	}

	/**
	 * 校验数字签名
	 * 
	 * @param data
	 *            加密数据
	 * @param publicKey
	 *            公钥
	 * @param sign
	 *            数字签名
	 * @return
	 * @throws Exception
	 */
	public static boolean verify(byte[] data, String publicKey, String sign)
			throws Exception {
		try {
			// 解密公钥
			byte[] keyBytes = decryptBASE64(publicKey);
			// 构造X509EncodedKeySpec对象
			X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
					keyBytes);
			// 指定加密算法
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
			// 取公钥匙对象
			PublicKey publicKey2 = keyFactory
					.generatePublic(x509EncodedKeySpec);

			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initVerify(publicKey2);
			signature.update(data);
			// 验证签名是否正常
			return signature.verify(decryptBASE64(sign));
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * Base64编码
	 * 
	 * @param str
	 * @return
	 * @throws IOException
	 */
	private static byte[] decryptBASE64(String str) throws IOException {
		return (new BASE64Decoder()).decodeBuffer(str);
	}

	/**
	 * Base64解码
	 * 
	 * @param b
	 * @return
	 */
	private static String encryptBASE64(byte[] b) {
		return (new BASE64Encoder()).encode(b);
	}

	/**
	 * 生成秘钥
	 * 
	 * @param filePath
	 * @throws NoSuchAlgorithmException
	 */
	public static void genKeyPair(String filePath)
			throws NoSuchAlgorithmException {
		KeyPairGenerator keyPairGenerator = KeyPairGenerator
				.getInstance(KEY_ALGORTHM);
		keyPairGenerator.initialize(1024);
		KeyPair keyPair = keyPairGenerator.generateKeyPair();

		// 公钥
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		// 私钥
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		try {
			// 得到公钥字符串
			String publicKeyString = encryptBASE64(publicKey.getEncoded());
			// 得到私钥字符串
			String privateKeyString = encryptBASE64(privateKey.getEncoded());
			// 将密钥对写入到文件
			FileWriter pubfw = new FileWriter(filePath + "/publicKey.keystore");
			FileWriter prifw = new FileWriter(filePath + "/privateKey.keystore");
			BufferedWriter pubbw = new BufferedWriter(pubfw);
			BufferedWriter pribw = new BufferedWriter(prifw);
			pubbw.write(publicKeyString);
			pribw.write(privateKeyString);
			pubbw.flush();
			pubbw.close();
			pubfw.close();
			pribw.flush();
			pribw.close();
			prifw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
